﻿
using CSRedis;
using Himp.TaskScheduling.Hangfire;
using Microsoft.Extensions.Options;
using System.IO;

namespace Himp.TaskScheduling
{
    /// <summary>
    /// 
    /// </summary>
    public class RedisToMqttWorker : IHostedService, IDisposable
    {
        private CSRedisClient _client;
        private Timer _timer;
        private readonly TimeSpan _interval = TimeSpan.FromMilliseconds(50);
        private readonly TimeSpan _delay = TimeSpan.FromMilliseconds(0);
        private bool _isExecuting = false;
        Dictionary<string, object> keyValuePairs = new Dictionary<string, object>();
        private static readonly object _lock = new object();
        private bool _init = false;
        private ILogger<RedisToMqttWorker> _logger;
        private readonly ConnectionStringOption _connectionStrings;

        public RedisToMqttWorker(ILogger<RedisToMqttWorker> logger
            , IOptions<ConnectionStringOption> connectionStrings)
        {
            _connectionStrings = connectionStrings.Value;
            _logger = logger;
            // 初始化计时器，初始时不启动，等待 StartAsync 启动
            _timer = new Timer(ExecuteJob, null, _delay, Timeout.InfiniteTimeSpan);
            _client = new CSRedis.CSRedisClient(_connectionStrings.KaiYRedis);
            RedisHelper.Initialization(_client);
            _init = true;
        }

        private async void ExecuteJob(object state)
        {
            if (_isExecuting || !_init)
            {
                // 如果任务正在执行，则跳过
                return;
            }

            lock (_lock)
            {
                if (_isExecuting)
                {
                    return;
                }
                _isExecuting = true;
            }

            try
            {
                // 你的任务逻辑
                await RunAsync();

            }
            catch (Exception e)
            {
                await Console.Out.WriteLineAsync(e.Message);
            }
            finally
            {
                GC.Collect(0);
                lock (_lock)
                {
                    _isExecuting = false;
                }
                // 任务完成后重新设置计时器
                _timer.Change(_interval, Timeout.InfiniteTimeSpan);
            }
        }

        private async Task RunAsync()
        {
            var keys = RedisHelper.Keys("*");

            if (MqttClientHelper.Connected)
            {
                var tasks = keys.Where(k => !k.EndsWith(":Point") && !k.EndsWith(":Stamp")).Select(async key =>
                {
                    Console.WriteLine(key);
                    var v = await RedisHelper.GetAsync(key);

                    lock (_lock)
                    {
                        if (keyValuePairs.ContainsKey(key))
                        {
                            if (string.Equals(keyValuePairs[key], v))
                            {
                                return;
                            }
                            keyValuePairs[key] = v;
                        }
                        else
                        {
                            keyValuePairs.Add(key, v);
                        }
                    }

                    var keyPath = key.Split(":");

                    if (keyPath.Length > 3)
                    {
                        await MqttClientHelper.PublishStringAsync(keyPath[0] +"/"+ keyPath[1], $"{keyPath[2]}:{v}");
                    }

                    //var path = await RedisHelper.GetAsync($"TopicKeyPath:{key}");

                    //if (path != null && !string.IsNullOrEmpty(path.ToString()))
                    //{
                    //    await MqttClientHelper.PublishStringAsync(path.ToString(), $"{key}:{v}");
                    //}
                });

                await Task.WhenAll(tasks);
            }
            //else
            //{

            //}
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            _timer.Change(_delay, _interval);
            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _timer?.Dispose();
            return Task.CompletedTask;
        }

        public void Dispose()
        {
            _timer?.Dispose();
        }
    }
}
